#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <cstdlib>

namespace Http_Ns
{

    enum
    {
        ParseLineErr = 1,
        ParseReqLineErr,
        OpenFileErr,
        ReadFileErr,

    };

    const std::string HttpSep = "\r\n";
    const std::string ReqPackageSep = " ";

    class Request
    {
    private:
        bool ParseLine(std::string &request, std::string *out)
        {
            int pos = request.find(HttpSep);
            if (pos == std::string::npos)
            {
                *out = "";
                return false;
            }
            *out = request.substr(0, pos);
            request.erase(0, pos + HttpSep.size());
            return true;
        }

        bool ParseReqLine(const std::string &req_line)
        {
            int left = req_line.find(ReqPackageSep);
            if (left == std::string::npos)
                return false;
            int right = req_line.rfind(ReqPackageSep);
            if (right == std::string::npos)
                return false;

            _method = req_line.substr(0, left);
            _url = req_line.substr(left + ReqPackageSep.size(), right - (left + ReqPackageSep.size()));
            _version = req_line.substr(right);

            return true;
        }

    public:
        Request() : _empty_row("\r\n")
        {
        }

        void Analyzing(std::string &request)
        {
            // 1. 解析请求行
            std::string req_line;
            if (!ParseLine(request, &req_line))
                exit(ParseLineErr);
            if (!ParseReqLine(req_line))
                exit(ParseReqLineErr);
            // 2. 解析请求报头
            while (true)
            {
                std::string reqpackage;
                if (ParseLine(request, &reqpackage))
                {
                    if (reqpackage.empty())
                        break;
                    else
                    {
                        _req_package.push_back(reqpackage);
                    }
                }
                else
                    exit(ParseLineErr);
            }
            // 3. 获取请求正文
            _content = request;
        }

        std::string Url()
        {
            return _url;
        }

        void Debug()
        {
            std::cout << "Method---> " << _method << std::endl;
            std::cout << "Url---> " << _url << std::endl;
            std::cout << "Version---> " << _version << std::endl;
            for (auto &e : _req_package)
            {
                std::cout << e << std::endl;
            }
            std::cout << _empty_row;
            std::cout << "Content---> " << _content << std::endl;
        }

        ~Request()
        {
        }

    private:
        std::string _method;
        std::string _version;
        std::string _url;
        std::string _empty_row;
        std::vector<std::string> _req_package;
        std::string _content;
    };

    const std::string root = "./web";
    const std::string home = "/index.html";
    const std::string suffix = ".";

    class Response
    {
    private:
        std::string Path(std::string &url)
        {
            if (url == "/")
            {
                return root + home;
            }
            else
            {
                return root + url;
                // return root + home;
                // std::string path = root + url;
            }
        }
        std::string GetContent(const std::string &path)
        {
            // std::ifstream file(path);
            // if (!file.is_open())
            // {
            //     throw std::runtime_error("Could not open file for reading");
            // }

            // std::string lines;
            // std::string line;
            // while (std::getline(file, line))
            // {
            //     lines += line;
            // }
            // file.close();
            // return lines;
            // std::cout << "Path######: " << path << std::endl;
            // std::ifstream in(path, std::ios::binary);
            // if (!in)
            // {
            //     std::cout << "打开文件" << path << "失败" << std::endl;
            //     exit(OpenFileErr);
            // }

            // std::streamsize size = in.tellg();
            // string content;
            // content.resize(size);
            // in.seekg(0, std::ios::beg);
            // if (in.read((char*)content.c_str(), size))
            // {
            //     in.close();
            //     return content;
            // }
            // else
            // {
            //     exit(ReadFileErr);
            // }

            std::ifstream in(path, std::ios::binary);
            if (!in.is_open())
                return "";
            in.seekg(0, in.end);
            int filesize = in.tellg();
            in.seekg(0, in.beg);

            std::string content;
            content.resize(filesize);
            in.read((char *)content.c_str(), filesize);

            in.close();

            return content;
        }

        std::string GetSuffix(const std::string url)
        {
            int pos = url.rfind(suffix);

            std::cout << "########Url : " << url << std::endl;
            if (_type_cv.count(url.substr(pos + suffix.size())))
            {
                return "Content-Type: " + _type_cv[url.substr(pos + 1)];
            }
            else
                return "";
        }

    public:
        Response()
        {
            _type_cv.insert(make_pair("html", "text/html"));
            _type_cv.insert(make_pair("png", "image/png"));
        }

        std::string HttpResponse(Http_Ns::Request &req)
        {
            std::string url = req.Url();
            std::string content = GetContent(Path(url));
            // std::vector<char> content;

            std::string httpstatusline = "Http/1.0 200 OK" + HttpSep;
            // std::string contenttype = GetSuffix(Path(url)) + HttpSep;
            std::string httpheader = "Content-Length: " + std::to_string(content.size()) + HttpSep;
            std::string response = httpstatusline + httpheader +
                                   HttpSep +
                                   content;
            std::cout << "Content######: " << content << std::endl;
            return response;
        }

    private:
        std::unordered_map<std::string, std::string> _type_cv;
    };
}
